package workflow

import (
	"fmt"
	"strconv"
	"time"

	"shqsoft.cn/pasnj/base"
	"shqsoft.cn/pasnj/popedom"
	"shqsoft.cn/pasnj/workflow/entity"

	"github.com/jinzhu/gorm"
)

//RunInfo 流程运行信息
type RunInfo struct {
	RunID    int        `json:"runID"`
	WFID     int        `json:"wfid"`
	CurrStep int        `json:"currStep"`
	State    string     `json:"state"`
	StepList []StepItem `json:"stepList"`
}

//StepItem 流程运行过程项
type StepItem struct {
	ID        int        `json:"id"`
	Name      string     `json:"name"`
	State     string     `json:"state"`
	CanBack   bool       `json:"canBack"`
	Executors []Executor `json:"executors"`
	Appointer []string   `json:"appointer"`
	MustDesc  bool       `json:"mustDesc"`
}

//Executor 执行人
type Executor struct {
	ID         int    `json:"id"`
	Name       string `json:"name"`
	Department string `json:"department"`
	Desc       string `json:"desc"`
}

//GetRecorder 获取的备案人
func GetRecorder(wfid int) ([]string, error) {
	wf := GetWorkFlow(wfid)
	if wf == nil {
		return nil, fmt.Errorf("流程ID:%d在配置中不存在！", wfid)
	}
	if wf.Recorder == "" {
		return nil, nil
	}
	roleID, err := strconv.Atoi(wf.Recorder)
	if err != nil {
		return nil, fmt.Errorf("流程%d配置错误，流程的manager应该配置为角色ID！", wfid)
	}
	userIds, err := popedom.GetRoleUsersFormRedis(roleID)
	if err != nil {
		return nil, err
	}
	return userIds, nil
}

//GetAppointer 获取流程节点的设置人
func GetAppointer(wfid int) (map[int][]string, error) {
	wf := GetWorkFlow(wfid)
	if wf == nil {
		return nil, fmt.Errorf("流程ID:%d在配置中不存在！", wfid)
	}
	aper := make(map[int][]string, 5)
	for _, act := range wf.Actions {
		if act.Appointer == "" {
			continue
		}
		roleID, err := strconv.Atoi(act.Appointer)
		if err != nil {
			return nil, fmt.Errorf("流程%d配置错误，节点%d中的appointer应该配置为角色ID！", wfid, act.Step)
		}
		if act.Appointer != "" {
			userIds, err := popedom.GetRoleUsersFormRedis(roleID)
			if err != nil {
				return nil, err
			}
			aper[act.Step] = userIds
		}
	}
	return aper, nil
}

//GetRunInfo 获取流程运行信息
func GetRunInfo(runID int) (runInfo *RunInfo, err error) {
	run := entity.FlowRun{}
	tx := base.DB.Begin()
	if err = tx.First(&run, runID).Error; err != nil {
		tx.Rollback()
		return
	}
	wf := GetWorkFlow(run.WFID)
	if wf == nil {
		tx.Rollback()
		return nil, fmt.Errorf("流程ID:%d在配置中不存在！", run.WFID)
	}
	alen := len(wf.Actions)
	list := make([]StepItem, alen, alen)
	cache := base.GetEmployeeCache()
	for i, act := range wf.Actions {
		si := StepItem{
			ID:       act.Step,
			Name:     act.Desc,
			State:    "0",
			CanBack:  act.CanBack,
			MustDesc: act.MustDesc,
		}
		if run.Step == 0 || run.Step > act.Step || run.State == "1" {
			si.State = "2"
		} else if run.Step == act.Step && run.State == "0" {
			si.State = "1"
		}
		userids, _, descs, err := getExecutor(tx, runID, act.Step, true)
		if err != nil {
			tx.Rollback()
			return nil, err
		}
		executors := make([]Executor, len(userids), len(userids))
		for j, uid := range userids {
			uName, _ := cache.GetNameByID(uid)
			oName, _ := cache.GetDeptNameByID(uid)
			executors[j] = Executor{
				ID:         uid,
				Name:       uName,
				Department: oName,
				Desc:       descs[j],
			}
		}
		si.Executors = executors
		if act.Appointer != "" {
			roleID, err := strconv.Atoi(act.Appointer)
			if err != nil {
				tx.Rollback()
				return nil, fmt.Errorf("流程%d配置错误，节点%d中的appointer应该配置为角色ID！", run.WFID, act.Step)
			}
			si.Appointer, err = popedom.GetRoleUsersFormRedis(roleID)
			if err != nil {
				tx.Rollback()
				return nil, err
			}
		}
		list[i] = si
	}
	runInfo = &RunInfo{
		RunID:    runID,
		WFID:     wf.ID,
		CurrStep: run.Step,
		State:    run.State,
		StepList: list,
	}
	if runInfo.CurrStep == 0 {
		runInfo.CurrStep = len(list)
	}
	tx.Commit()
	return
}

//GetRunInfo 获取流程运行信息 查看2021年7月之前的数据
func GetRunInfoBak(runID int) (runInfo *RunInfo, err error) {
	run := entity.FlowRunBak{}
	tx := base.DB.Begin()
	if err = tx.First(&run, runID).Error; err != nil {
		tx.Rollback()
		return
	}
	wf := GetWorkFlow(run.WFID)
	if wf == nil {
		tx.Rollback()
		return nil, fmt.Errorf("流程ID:%d在配置中不存在！", run.WFID)
	}
	alen := len(wf.Actions)
	list := make([]StepItem, alen, alen)
	cache := base.GetEmployeeCache()
	for i, act := range wf.Actions {
		si := StepItem{
			ID:       act.Step,
			Name:     act.Desc,
			State:    "0",
			CanBack:  act.CanBack,
			MustDesc: act.MustDesc,
		}
		if run.Step == 0 || run.Step > act.Step || run.State == "1" {
			si.State = "2"
		} else if run.Step == act.Step && run.State == "0" {
			si.State = "1"
		}
		userids, _, descs, err := getExecutorBak(tx, runID, act.Step, true)
		if err != nil {
			tx.Rollback()
			return nil, err
		}
		executors := make([]Executor, len(userids), len(userids))
		for j, uid := range userids {
			uName, _ := cache.GetNameByID(uid)
			oName, _ := cache.GetDeptNameByID(uid)
			executors[j] = Executor{
				ID:         uid,
				Name:       uName,
				Department: oName,
				Desc:       descs[j],
			}
		}
		si.Executors = executors
		if act.Appointer != "" {
			roleID, err := strconv.Atoi(act.Appointer)
			if err != nil {
				tx.Rollback()
				return nil, fmt.Errorf("流程%d配置错误，节点%d中的appointer应该配置为角色ID！", run.WFID, act.Step)
			}
			si.Appointer, err = popedom.GetRoleUsersFormRedis(roleID)
			if err != nil {
				tx.Rollback()
				return nil, err
			}
		}
		list[i] = si
	}
	runInfo = &RunInfo{
		RunID:    runID,
		WFID:     wf.ID,
		CurrStep: run.Step,
		State:    run.State,
		StepList: list,
	}
	if runInfo.CurrStep == 0 {
		runInfo.CurrStep = len(list)
	}
	tx.Commit()
	return
}
func createStep(tx *gorm.DB, runID int, step int, userIds []int) (err error) {
	uLen := len(userIds)
	steps := make([]entity.FlowRunStep, uLen, uLen)
	for i := 0; i < uLen; i++ {
		steps[i] = entity.FlowRunStep{
			RunID:     runID,
			StepID:    step,
			EMID:      userIds[i],
			StartTime: time.Now(),
			State:     "0",
		}
		err = tx.Create(&steps[i]).Error
		if err != nil {
			return
		}
	}
	return
}

func startStep(tx *gorm.DB, runID int, step int, userID int) (err error) {
	runStep := entity.FlowRunStep{}
	tx.Where(entity.FlowRunStep{RunID: runID, StepID: step, EMID: userID}).FirstOrInit(&runStep)
	if runStep.RunID > 0 {
		runStep.StartTime = time.Now()
		runStep.State = "0"
		err = tx.Create(&runStep).Error
		if err != nil {
			return
		}
	}
	return
}

func finishStep(tx *gorm.DB, runID int, step int, userID int, toStep int, submitType, desc string, conSign bool) (finish bool, err error) {
	runSteps := []entity.FlowRunStep{}
	whereEnt := entity.FlowRunStep{RunID: runID, StepID: step}
	if conSign {
		whereEnt.EMID = userID
	}
	err = tx.Where(whereEnt).Where("STATE in (0,1)").Find(&runSteps).Error
	if err != nil || len(runSteps) == 0 {
		return false, fmt.Errorf("不是在办任务，不能提交！")
	}
	now := time.Now()
	isOK := false
	for _, runStep := range runSteps {
		if userID == runStep.EMID {
			isOK = true
		}
	}
	if !isOK {
		return false, fmt.Errorf("不是在办任务，不能提交！")
	}
	for _, runStep := range runSteps {
		if runStep.RunID > 0 {
			if runStep.EMID == userID {
				runStep.State = "2"
			} else {
				runStep.State = "3"
			}
			runStep.ToStepID = toStep
			runStep.SubmitTime = &now
			runStep.SubmitType = submitType
			//runStep.Description = desc
			err = tx.Save(&runStep).Error
			if err != nil {
				return
			}
		}
	}
	return isAllFinish(tx, runID, step)
}

func isAllFinish(tx *gorm.DB, runID int, step int) (finish bool, err error) {
	var count int
	err = tx.Model(entity.FlowRunStep{}).Where(entity.FlowRunStep{RunID: runID, StepID: step}).Where("STATE in (0,1)").Count(&count).Error
	if err != nil {
		return
	}
	if count == 0 {
		finish = true
	}
	return
}
